{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# 创建子图 (Subplots) 教程\n",
        "\n",
        "本部分将详细讲解如何使用 Matplotlib 创建子图，包括三种主要方法：`plt.subplot()`、`plt.subplots()` 和 `GridSpec`。\n",
        "\n",
        "## 学习内容\n",
        "1. **使用 plt.subplot()**\n",
        "   - `plt.subplot(nrows, ncols, index)` 创建子图\n",
        "   - 索引从 1 开始\n",
        "   - 当前子图切换\n",
        "\n",
        "2. **使用 plt.subplots()**\n",
        "   - `fig, axes = plt.subplots(nrows, ncols)` 创建子图网格\n",
        "   - 返回图形对象和坐标轴数组\n",
        "   - `sharex` 和 `sharey` 参数：共享坐标轴\n",
        "   - `figsize` 参数：整体图形大小\n",
        "\n",
        "3. **使用 GridSpec**\n",
        "   - 创建复杂的不规则子图布局\n",
        "   - 跨行跨列的子图\n",
        "   - 灵活的子图排列方式\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 导入必要的库\n",
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "from matplotlib.gridspec import GridSpec\n",
        "\n",
        "# 设置中文字体（如果需要显示中文）\n",
        "plt.rcParams['font.sans-serif'] = ['PingFang SC', 'Arial Unicode MS']\n",
        "plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题\n",
        "\n",
        "# 在 Jupyter Notebook 中内联显示图形\n",
        "%matplotlib inline\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 第一部分：使用 plt.subplot()\n",
        "\n",
        "`plt.subplot()` 是最基础的创建子图的方法，它可以在当前图形中创建或切换到指定的子图位置。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 1.1 plt.subplot() 基本语法\n",
        "\n",
        "`plt.subplot()` 用于创建或切换到指定的子图位置。\n",
        "\n",
        "**基本语法**：\n",
        "```python\n",
        "plt.subplot(nrows, ncols, index)\n",
        "```\n",
        "\n",
        "**参数说明**：\n",
        "- `nrows`：子图网格的行数\n",
        "- `ncols`：子图网格的列数\n",
        "- `index`：子图的位置索引（从 1 开始，从左到右、从上到下编号）\n",
        "\n",
        "**索引规则**：\n",
        "- 索引从 1 开始（不是从 0 开始）\n",
        "- 按行优先顺序编号：第一行从左到右，然后是第二行，以此类推\n",
        "- 例如：`plt.subplot(2, 2, 1)` 表示 2×2 网格中的第 1 个位置（左上角）\n",
        "\n",
        "**返回值**：\n",
        "- 返回一个 `Axes` 对象，表示当前活动的子图\n",
        "\n",
        "**注意事项**：\n",
        "- 每次调用 `plt.subplot()` 都会切换到对应的子图\n",
        "- 后续的绘图操作会在当前活动的子图上进行\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 1：基础子图创建 - 2×2 网格\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建 2×2 的子图网格\n",
        "plt.figure(figsize=(10, 8))\n",
        "\n",
        "# 第一个子图（左上角，索引 1）\n",
        "plt.subplot(2, 2, 1)\n",
        "plt.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "plt.title('子图 1: sin(x)', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "# 第二个子图（右上角，索引 2）\n",
        "plt.subplot(2, 2, 2)\n",
        "plt.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "plt.title('子图 2: cos(x)', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "# 第三个子图（左下角，索引 3）\n",
        "plt.subplot(2, 2, 3)\n",
        "plt.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "plt.title('子图 3: tan(x)', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "plt.ylim(-5, 5)  # 限制 y 轴范围，因为 tan(x) 会趋于无穷\n",
        "\n",
        "# 第四个子图（右下角，索引 4）\n",
        "plt.subplot(2, 2, 4)\n",
        "plt.plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "plt.title('子图 4: sin(x) * cos(x)', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "plt.tight_layout()  # 自动调整布局\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 1.2 索引从 1 开始的重要性\n",
        "\n",
        "**重要提示**：`plt.subplot()` 的索引从 1 开始，不是从 0 开始！\n",
        "\n",
        "这是初学者常犯的错误。如果使用索引 0，会导致错误或意外的行为。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 2：演示索引从 1 开始\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "plt.figure(figsize=(12, 4))\n",
        "\n",
        "# 正确：索引从 1 开始\n",
        "plt.subplot(1, 3, 1)  # 第一个子图\n",
        "plt.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "plt.title('正确：索引 1', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "plt.subplot(1, 3, 2)  # 第二个子图\n",
        "plt.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "plt.title('正确：索引 2', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "plt.subplot(1, 3, 3)  # 第三个子图\n",
        "plt.plot(x, np.sin(x) * np.cos(x), 'g-', linewidth=2)\n",
        "plt.title('正确：索引 3', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 注意：如果使用索引 0，会报错或产生意外结果\n",
        "# plt.subplot(1, 3, 0)  # 这会报错！\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 1.3 不同网格布局示例\n",
        "\n",
        "`plt.subplot()` 可以创建各种不同大小的网格布局。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 3：不同网格布局\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 1×3 布局（一行三列）\n",
        "plt.figure(figsize=(15, 4))\n",
        "for i in range(3):\n",
        "    plt.subplot(1, 3, i+1)\n",
        "    plt.plot(x, np.sin(x + i), 'b-', linewidth=2)\n",
        "    plt.title(f'1×3 布局：子图 {i+1}', fontsize=12)\n",
        "    plt.grid(True, alpha=0.3)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 3×1 布局（三行一列）\n",
        "plt.figure(figsize=(6, 12))\n",
        "for i in range(3):\n",
        "    plt.subplot(3, 1, i+1)\n",
        "    plt.plot(x, np.sin(x + i), 'r-', linewidth=2)\n",
        "    plt.title(f'3×1 布局：子图 {i+1}', fontsize=12)\n",
        "    plt.grid(True, alpha=0.3)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 2×3 布局（两行三列）\n",
        "plt.figure(figsize=(15, 8))\n",
        "for i in range(6):\n",
        "    plt.subplot(2, 3, i+1)\n",
        "    plt.plot(x, np.sin(x + i*0.5), 'g-', linewidth=2)\n",
        "    plt.title(f'2×3 布局：子图 {i+1}', fontsize=12)\n",
        "    plt.grid(True, alpha=0.3)\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 第二部分：使用 plt.subplots()\n",
        "\n",
        "`plt.subplots()` 是更现代和推荐的方法，它一次性创建所有子图并返回图形对象和坐标轴数组，使用起来更加方便。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 2.1 plt.subplots() 基本语法\n",
        "\n",
        "`plt.subplots()` 一次性创建所有子图，并返回图形对象和坐标轴数组。\n",
        "\n",
        "**基本语法**：\n",
        "```python\n",
        "fig, axes = plt.subplots(nrows, ncols, figsize=(width, height))\n",
        "```\n",
        "\n",
        "**参数说明**：\n",
        "- `nrows`：子图网格的行数\n",
        "- `ncols`：子图网格的列数\n",
        "- `figsize`：整体图形大小（宽度, 高度），单位为英寸\n",
        "- `sharex`：是否共享 x 轴（可选：`True`, `False`, `'row'`, `'col'`, `'all'`, `'none'`）\n",
        "- `sharey`：是否共享 y 轴（可选：`True`, `False`, `'row'`, `'col'`, `'all'`, `'none'`）\n",
        "\n",
        "**返回值**：\n",
        "- `fig`：图形对象（Figure 对象）\n",
        "- `axes`：坐标轴数组（Axes 对象或数组）\n",
        "  - 如果只有一个子图：`axes` 是单个 Axes 对象\n",
        "  - 如果是一维数组：`axes` 是一维数组\n",
        "  - 如果是二维数组：`axes` 是二维数组\n",
        "\n",
        "**优势**：\n",
        "- 一次性创建所有子图，代码更简洁\n",
        "- 可以直接通过索引访问每个子图\n",
        "- 更容易管理图形对象\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 4：基础 plt.subplots() 使用\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建 2×2 的子图网格\n",
        "fig, axes = plt.subplots(2, 2, figsize=(10, 8))\n",
        "\n",
        "# 访问子图并绘图\n",
        "# axes 是二维数组，使用 axes[row, col] 访问\n",
        "axes[0, 0].plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "axes[0, 0].set_title('子图 (0,0): sin(x)', fontsize=12)\n",
        "axes[0, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[0, 1].plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "axes[0, 1].set_title('子图 (0,1): cos(x)', fontsize=12)\n",
        "axes[0, 1].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 0].plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "axes[1, 0].set_title('子图 (1,0): tan(x)', fontsize=12)\n",
        "axes[1, 0].grid(True, alpha=0.3)\n",
        "axes[1, 0].set_ylim(-5, 5)\n",
        "\n",
        "axes[1, 1].plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "axes[1, 1].set_title('子图 (1,1): sin(x) * cos(x)', fontsize=12)\n",
        "axes[1, 1].grid(True, alpha=0.3)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 2.2 坐标轴数组的访问方式\n",
        "\n",
        "理解 `axes` 数组的访问方式很重要，它取决于子图的数量和布局。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 5：不同布局下的 axes 访问方式\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 情况 1：单个子图\n",
        "fig, ax = plt.subplots(figsize=(6, 4))\n",
        "ax.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax.set_title('单个子图：ax 是单个 Axes 对象', fontsize=12)\n",
        "ax.grid(True, alpha=0.3)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 情况 2：一行多列（一维数组）\n",
        "fig, axes = plt.subplots(1, 3, figsize=(15, 4))\n",
        "print(f\"axes 类型: {type(axes)}, 形状: {axes.shape}\")\n",
        "for i, ax in enumerate(axes):\n",
        "    ax.plot(x, np.sin(x + i), 'b-', linewidth=2)\n",
        "    ax.set_title(f'一维数组：axes[{i}]', fontsize=12)\n",
        "    ax.grid(True, alpha=0.3)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 情况 3：多行多列（二维数组）\n",
        "fig, axes = plt.subplots(2, 2, figsize=(10, 8))\n",
        "print(f\"axes 类型: {type(axes)}, 形状: {axes.shape}\")\n",
        "# 使用 flatten() 可以展平为一维数组\n",
        "for i, ax in enumerate(axes.flatten()):\n",
        "    ax.plot(x, np.sin(x + i*0.5), 'b-', linewidth=2)\n",
        "    ax.set_title(f'二维数组：axes.flatten()[{i}]', fontsize=12)\n",
        "    ax.grid(True, alpha=0.3)\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 2.3 sharex 和 sharey：共享坐标轴\n",
        "\n",
        "`sharex` 和 `sharey` 参数可以让多个子图共享相同的坐标轴，这在比较数据时非常有用。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 6：共享坐标轴\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 不共享坐标轴（默认）\n",
        "fig, axes = plt.subplots(2, 2, figsize=(12, 8))\n",
        "axes[0, 0].plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "axes[0, 0].set_title('不共享坐标轴', fontsize=12)\n",
        "axes[0, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[0, 1].plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "axes[0, 1].set_title('不共享坐标轴', fontsize=12)\n",
        "axes[0, 1].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 0].plot(x, np.sin(x) * 2, 'g-', linewidth=2)\n",
        "axes[1, 0].set_title('不共享坐标轴', fontsize=12)\n",
        "axes[1, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 1].plot(x, np.cos(x) * 2, 'm-', linewidth=2)\n",
        "axes[1, 1].set_title('不共享坐标轴', fontsize=12)\n",
        "axes[1, 1].grid(True, alpha=0.3)\n",
        "\n",
        "plt.suptitle('不共享坐标轴（默认）', fontsize=14, y=1.02)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 共享 x 轴\n",
        "fig, axes = plt.subplots(2, 2, figsize=(12, 8), sharex=True)\n",
        "axes[0, 0].plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "axes[0, 0].set_title('共享 x 轴', fontsize=12)\n",
        "axes[0, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[0, 1].plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "axes[0, 1].set_title('共享 x 轴', fontsize=12)\n",
        "axes[0, 1].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 0].plot(x, np.sin(x) * 2, 'g-', linewidth=2)\n",
        "axes[1, 0].set_title('共享 x 轴', fontsize=12)\n",
        "axes[1, 0].set_xlabel('x 轴', fontsize=10)\n",
        "axes[1, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 1].plot(x, np.cos(x) * 2, 'm-', linewidth=2)\n",
        "axes[1, 1].set_title('共享 x 轴', fontsize=12)\n",
        "axes[1, 1].set_xlabel('x 轴', fontsize=10)\n",
        "axes[1, 1].grid(True, alpha=0.3)\n",
        "\n",
        "plt.suptitle('共享 x 轴 (sharex=True)', fontsize=14, y=1.02)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 共享 y 轴\n",
        "fig, axes = plt.subplots(2, 2, figsize=(12, 8), sharey=True)\n",
        "axes[0, 0].plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "axes[0, 0].set_title('共享 y 轴', fontsize=12)\n",
        "axes[0, 0].set_ylabel('y 轴', fontsize=10)\n",
        "axes[0, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[0, 1].plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "axes[0, 1].set_title('共享 y 轴', fontsize=12)\n",
        "axes[0, 1].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 0].plot(x, np.sin(x) * 2, 'g-', linewidth=2)\n",
        "axes[1, 0].set_title('共享 y 轴', fontsize=12)\n",
        "axes[1, 0].set_ylabel('y 轴', fontsize=10)\n",
        "axes[1, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 1].plot(x, np.cos(x) * 2, 'm-', linewidth=2)\n",
        "axes[1, 1].set_title('共享 y 轴', fontsize=12)\n",
        "axes[1, 1].grid(True, alpha=0.3)\n",
        "\n",
        "plt.suptitle('共享 y 轴 (sharey=True)', fontsize=14, y=1.02)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 同时共享 x 和 y 轴\n",
        "fig, axes = plt.subplots(2, 2, figsize=(12, 8), sharex=True, sharey=True)\n",
        "axes[0, 0].plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "axes[0, 0].set_title('共享 x 和 y 轴', fontsize=12)\n",
        "axes[0, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[0, 1].plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "axes[0, 1].set_title('共享 x 和 y 轴', fontsize=12)\n",
        "axes[0, 1].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 0].plot(x, np.sin(x) * 2, 'g-', linewidth=2)\n",
        "axes[1, 0].set_title('共享 x 和 y 轴', fontsize=12)\n",
        "axes[1, 0].set_xlabel('x 轴', fontsize=10)\n",
        "axes[1, 0].set_ylabel('y 轴', fontsize=10)\n",
        "axes[1, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 1].plot(x, np.cos(x) * 2, 'm-', linewidth=2)\n",
        "axes[1, 1].set_title('共享 x 和 y 轴', fontsize=12)\n",
        "axes[1, 1].set_xlabel('x 轴', fontsize=10)\n",
        "axes[1, 1].grid(True, alpha=0.3)\n",
        "\n",
        "plt.suptitle('同时共享 x 和 y 轴 (sharex=True, sharey=True)', fontsize=14, y=1.02)\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": []
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 7：不同 figsize 的效果\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 小图形\n",
        "fig, axes = plt.subplots(2, 2, figsize=(6, 4))\n",
        "for i, ax in enumerate(axes.flatten()):\n",
        "    ax.plot(x, np.sin(x + i*0.5), 'b-', linewidth=2)\n",
        "    ax.set_title(f'figsize=(6, 4)', fontsize=10)\n",
        "    ax.grid(True, alpha=0.3)\n",
        "plt.suptitle('小图形：figsize=(6, 4)', fontsize=12, y=1.02)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 标准图形\n",
        "fig, axes = plt.subplots(2, 2, figsize=(10, 8))\n",
        "for i, ax in enumerate(axes.flatten()):\n",
        "    ax.plot(x, np.sin(x + i*0.5), 'b-', linewidth=2)\n",
        "    ax.set_title(f'figsize=(10, 8)', fontsize=12)\n",
        "    ax.grid(True, alpha=0.3)\n",
        "plt.suptitle('标准图形：figsize=(10, 8)', fontsize=14, y=1.02)\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 宽图形（适合横向布局）\n",
        "fig, axes = plt.subplots(2, 3, figsize=(15, 8))\n",
        "for i, ax in enumerate(axes.flatten()):\n",
        "    ax.plot(x, np.sin(x + i*0.3), 'b-', linewidth=2)\n",
        "    ax.set_title(f'figsize=(15, 8)', fontsize=10)\n",
        "    ax.grid(True, alpha=0.3)\n",
        "plt.suptitle('宽图形：figsize=(15, 8)', fontsize=14, y=1.02)\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 第三部分：使用 GridSpec\n",
        "\n",
        "`GridSpec` 是创建复杂和不规则子图布局的强大工具，它允许创建跨行跨列的子图。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.1 GridSpec 基本语法\n",
        "\n",
        "`GridSpec` 提供了更灵活的子图布局方式，可以创建不规则和跨行跨列的子图。\n",
        "\n",
        "**基本语法**：\n",
        "```python\n",
        "from matplotlib.gridspec import GridSpec\n",
        "\n",
        "gs = GridSpec(nrows, ncols, figure=fig)\n",
        "ax = fig.add_subplot(gs[row, col])  # 或 gs[row_start:row_end, col_start:col_end]\n",
        "```\n",
        "\n",
        "**参数说明**：\n",
        "- `nrows`：网格的行数\n",
        "- `ncols`：网格的列数\n",
        "- `figure`：图形对象（可选）\n",
        "- `width_ratios`：列宽比例（可选）\n",
        "- `height_ratios`：行高比例（可选）\n",
        "\n",
        "**切片语法**：\n",
        "- `gs[0, 0]`：第 0 行第 0 列（单个单元格）\n",
        "- `gs[0, :]`：第 0 行的所有列\n",
        "- `gs[:, 0]`：第 0 列的所有行\n",
        "- `gs[0:2, 0:2]`：从 (0,0) 到 (1,1) 的矩形区域（跨行跨列）\n",
        "\n",
        "**优势**：\n",
        "- 可以创建不规则布局\n",
        "- 支持跨行跨列的子图\n",
        "- 可以设置行高和列宽比例\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 8：基础 GridSpec 使用\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建图形和 GridSpec\n",
        "fig = plt.figure(figsize=(12, 8))\n",
        "gs = GridSpec(3, 3, figure=fig)\n",
        "\n",
        "# 创建子图\n",
        "ax1 = fig.add_subplot(gs[0, :])  # 第一行，所有列（跨列）\n",
        "ax1.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax1.set_title('第一行，跨所有列', fontsize=12)\n",
        "ax1.grid(True, alpha=0.3)\n",
        "\n",
        "ax2 = fig.add_subplot(gs[1, 0])  # 第二行第一列\n",
        "ax2.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "ax2.set_title('第二行第一列', fontsize=12)\n",
        "ax2.grid(True, alpha=0.3)\n",
        "\n",
        "ax3 = fig.add_subplot(gs[1, 1:])  # 第二行，从第二列到最后一列（跨列）\n",
        "ax3.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "ax3.set_title('第二行，跨第二列到最后一列', fontsize=12)\n",
        "ax3.set_ylim(-5, 5)\n",
        "ax3.grid(True, alpha=0.3)\n",
        "\n",
        "ax4 = fig.add_subplot(gs[2, :2])  # 第三行，前两列（跨列）\n",
        "ax4.plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "ax4.set_title('第三行，前两列', fontsize=12)\n",
        "ax4.grid(True, alpha=0.3)\n",
        "\n",
        "ax5 = fig.add_subplot(gs[2, 2])  # 第三行第三列\n",
        "ax5.plot(x, np.sin(x) + np.cos(x), 'c-', linewidth=2)\n",
        "ax5.set_title('第三行第三列', fontsize=12)\n",
        "ax5.grid(True, alpha=0.3)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.2 跨行跨列的子图\n",
        "\n",
        "GridSpec 的强大之处在于可以轻松创建跨行跨列的子图。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 9：跨行跨列的子图\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 创建一个复杂的布局\n",
        "fig = plt.figure(figsize=(14, 10))\n",
        "gs = GridSpec(4, 4, figure=fig, hspace=0.3, wspace=0.3)\n",
        "\n",
        "# 大图：占据左上角 2×2 区域\n",
        "ax1 = fig.add_subplot(gs[0:2, 0:2])\n",
        "ax1.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax1.set_title('大图：跨 2×2 区域', fontsize=12, fontweight='bold')\n",
        "ax1.grid(True, alpha=0.3)\n",
        "\n",
        "# 右上角：占据第一行右侧两列\n",
        "ax2 = fig.add_subplot(gs[0, 2:])\n",
        "ax2.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "ax2.set_title('右上角：跨第一行右侧两列', fontsize=12)\n",
        "ax2.grid(True, alpha=0.3)\n",
        "\n",
        "# 中间右侧：占据第二行右侧两列\n",
        "ax3 = fig.add_subplot(gs[1, 2:])\n",
        "ax3.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "ax3.set_title('中间右侧：跨第二行右侧两列', fontsize=12)\n",
        "ax3.set_ylim(-5, 5)\n",
        "ax3.grid(True, alpha=0.3)\n",
        "\n",
        "# 底部：占据第三、四行的所有列\n",
        "ax4 = fig.add_subplot(gs[2:, :])\n",
        "ax4.plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "ax4.set_title('底部：跨第三、四行所有列', fontsize=12, fontweight='bold')\n",
        "ax4.grid(True, alpha=0.3)\n",
        "\n",
        "# 左下角小图：第三行第一列\n",
        "ax5 = fig.add_subplot(gs[2, 0])\n",
        "ax5.plot(x, np.sin(x) + np.cos(x), 'c-', linewidth=2)\n",
        "ax5.set_title('小图1', fontsize=10)\n",
        "ax5.grid(True, alpha=0.3)\n",
        "\n",
        "# 左下角小图：第三行第二列\n",
        "ax6 = fig.add_subplot(gs[2, 1])\n",
        "ax6.plot(x, np.sin(x) - np.cos(x), 'y-', linewidth=2)\n",
        "ax6.set_title('小图2', fontsize=10)\n",
        "ax6.grid(True, alpha=0.3)\n",
        "\n",
        "plt.suptitle('GridSpec 跨行跨列布局示例', fontsize=16, fontweight='bold', y=0.995)\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.3 width_ratios 和 height_ratios：设置比例\n",
        "\n",
        "GridSpec 允许通过 `width_ratios` 和 `height_ratios` 设置列宽和行高的比例。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 示例 10：使用 width_ratios 和 height_ratios\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 使用 width_ratios 和 height_ratios\n",
        "fig = plt.figure(figsize=(14, 8))\n",
        "# width_ratios=[1, 2, 1] 表示三列的宽度比例为 1:2:1\n",
        "# height_ratios=[2, 1] 表示两行的高度比例为 2:1\n",
        "gs = GridSpec(2, 3, figure=fig, width_ratios=[1, 2, 1], height_ratios=[2, 1])\n",
        "\n",
        "# 第一行第一列（窄）\n",
        "ax1 = fig.add_subplot(gs[0, 0])\n",
        "ax1.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax1.set_title('窄列 (width_ratios=1)', fontsize=12)\n",
        "ax1.grid(True, alpha=0.3)\n",
        "\n",
        "# 第一行第二列（宽，占据中间）\n",
        "ax2 = fig.add_subplot(gs[0, 1])\n",
        "ax2.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "ax2.set_title('宽列 (width_ratios=2)', fontsize=12)\n",
        "ax2.grid(True, alpha=0.3)\n",
        "\n",
        "# 第一行第三列（窄）\n",
        "ax3 = fig.add_subplot(gs[0, 2])\n",
        "ax3.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "ax3.set_title('窄列 (width_ratios=1)', fontsize=12)\n",
        "ax3.set_ylim(-5, 5)\n",
        "ax3.grid(True, alpha=0.3)\n",
        "\n",
        "# 第二行第一列（高行）\n",
        "ax4 = fig.add_subplot(gs[1, 0])\n",
        "ax4.plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "ax4.set_title('高行 (height_ratios=2)', fontsize=12)\n",
        "ax4.grid(True, alpha=0.3)\n",
        "\n",
        "# 第二行跨第二、三列\n",
        "ax5 = fig.add_subplot(gs[1, 1:])\n",
        "ax5.plot(x, np.sin(x) + np.cos(x), 'c-', linewidth=2)\n",
        "ax5.set_title('第二行跨两列', fontsize=12)\n",
        "ax5.grid(True, alpha=0.3)\n",
        "\n",
        "plt.suptitle('GridSpec 使用 width_ratios 和 height_ratios', fontsize=14, fontweight='bold')\n",
        "plt.tight_layout()\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 综合案例\n",
        "\n",
        "下面是一个综合案例，展示三种创建子图方法的实际应用。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 综合案例：比较三种方法\n",
        "x = np.linspace(0, 10, 100)\n",
        "\n",
        "# 方法 1：使用 plt.subplot()\n",
        "print(\"方法 1：使用 plt.subplot()\")\n",
        "plt.figure(figsize=(12, 8))\n",
        "\n",
        "plt.subplot(2, 2, 1)\n",
        "plt.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "plt.title('plt.subplot(2,2,1)', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "plt.subplot(2, 2, 2)\n",
        "plt.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "plt.title('plt.subplot(2,2,2)', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "plt.subplot(2, 2, 3)\n",
        "plt.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "plt.title('plt.subplot(2,2,3)', fontsize=12)\n",
        "plt.ylim(-5, 5)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "plt.subplot(2, 2, 4)\n",
        "plt.plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "plt.title('plt.subplot(2,2,4)', fontsize=12)\n",
        "plt.grid(True, alpha=0.3)\n",
        "\n",
        "plt.suptitle('方法 1：plt.subplot()', fontsize=14, fontweight='bold')\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 方法 2：使用 plt.subplots()\n",
        "print(\"\\n方法 2：使用 plt.subplots()\")\n",
        "fig, axes = plt.subplots(2, 2, figsize=(12, 8), sharex=True, sharey=False)\n",
        "\n",
        "axes[0, 0].plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "axes[0, 0].set_title('axes[0,0]', fontsize=12)\n",
        "axes[0, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[0, 1].plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "axes[0, 1].set_title('axes[0,1]', fontsize=12)\n",
        "axes[0, 1].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 0].plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "axes[1, 0].set_title('axes[1,0]', fontsize=12)\n",
        "axes[1, 0].set_ylim(-5, 5)\n",
        "axes[1, 0].grid(True, alpha=0.3)\n",
        "\n",
        "axes[1, 1].plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "axes[1, 1].set_title('axes[1,1]', fontsize=12)\n",
        "axes[1, 1].grid(True, alpha=0.3)\n",
        "\n",
        "fig.suptitle('方法 2：plt.subplots() (共享 x 轴)', fontsize=14, fontweight='bold')\n",
        "plt.tight_layout()\n",
        "plt.show()\n",
        "\n",
        "# 方法 3：使用 GridSpec（复杂布局）\n",
        "print(\"\\n方法 3：使用 GridSpec\")\n",
        "fig = plt.figure(figsize=(14, 8))\n",
        "gs = GridSpec(3, 3, figure=fig, hspace=0.4, wspace=0.4)\n",
        "\n",
        "# 大图占据左上角 2×2\n",
        "ax1 = fig.add_subplot(gs[0:2, 0:2])\n",
        "ax1.plot(x, np.sin(x), 'b-', linewidth=2)\n",
        "ax1.set_title('GridSpec[0:2, 0:2] - 大图', fontsize=12, fontweight='bold')\n",
        "ax1.grid(True, alpha=0.3)\n",
        "\n",
        "# 右上角\n",
        "ax2 = fig.add_subplot(gs[0, 2])\n",
        "ax2.plot(x, np.cos(x), 'r-', linewidth=2)\n",
        "ax2.set_title('GridSpec[0, 2]', fontsize=12)\n",
        "ax2.grid(True, alpha=0.3)\n",
        "\n",
        "# 中间右侧\n",
        "ax3 = fig.add_subplot(gs[1, 2])\n",
        "ax3.plot(x, np.tan(x), 'g-', linewidth=2)\n",
        "ax3.set_title('GridSpec[1, 2]', fontsize=12)\n",
        "ax3.set_ylim(-5, 5)\n",
        "ax3.grid(True, alpha=0.3)\n",
        "\n",
        "# 底部跨所有列\n",
        "ax4 = fig.add_subplot(gs[2, :])\n",
        "ax4.plot(x, np.sin(x) * np.cos(x), 'm-', linewidth=2)\n",
        "ax4.set_title('GridSpec[2, :] - 跨所有列', fontsize=12, fontweight='bold')\n",
        "ax4.grid(True, alpha=0.3)\n",
        "\n",
        "fig.suptitle('方法 3：GridSpec (复杂布局)', fontsize=14, fontweight='bold')\n",
        "plt.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": []
    }
  ],
  "metadata": {
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}
